mxBasePath = '/bower_components/mxgraph/src';
define([ 'require',
    'angular',
    'underscore',
    'mxgraph',
], function (require, angular, _) {
    return function ($rootScope, $scope, $routeParams, $http, RuleSerivce, Resource, $timeout, GillionMsg) {
        if (!mxClient.isBrowserSupported()) {
            mxUtils.error('Browser is not supported!', 200, false);
            return;
        }
        RuleSerivce.promises().then(function () {
            $scope.status=$rootScope.currPackage.status;
        });
        function TreeNodeShape() { }
        TreeNodeShape.prototype = new mxCylinder();
        TreeNodeShape.prototype.constructor = TreeNodeShape;
        TreeNodeShape.prototype.segment = 0;

        TreeNodeShape.prototype.redrawPath = function(path, x, y, w, h, isForeground) {
            var graph = this.state.view.graph;
            var hasChildren = graph.model.getOutgoingEdges(this.state.cell).length > 0;
            if (isForeground) {
                if (hasChildren) {
                    path.moveTo(w / 2, h + this.segment);
                    path.lineTo(w / 2, h);
                    path.end();
                }
            } else {
                path.moveTo(0, 0);
                path.lineTo(w, 0);
                path.lineTo(w, h);
                path.lineTo(0, h);
                path.close();
            }
        };
        mxCellRenderer.prototype.defaultShapes['treenode'] = TreeNodeShape;
        mxGraphView.prototype.updateFloatingTerminalPoint = function(edge, start, end, source) {
            var pt = null;
            if (source) {
                pt = new mxPoint(start.x + start.width / 2,
                    start.y + start.height + TreeNodeShape.prototype.segment);
            } else {
                pt = new mxPoint(start.x + start.width / 2, start.y);
            }
            edge.setAbsoluteTerminalPoint(pt, source);
        };

        var container = document.createElement('div');
        container.style.position = 'absolute';
        //container.style.overflow = 'hidden';
        container.style.left = '0px';
        container.style.top = '0px';
        container.style.right = '0px';
        container.style.bottom = '0px';
        if (mxClient.IS_IE) {
            new mxDivResizer(container);
        }

        var graph = new mxGraph(container);
        graph.keepEdgesInBackground = true;

        var style = graph.getStylesheet().getDefaultVertexStyle();
        style[mxConstants.STYLE_SHAPE] = 'treenode';
        style[mxConstants.STYLE_GRADIENTCOLOR] = 'white';
        style[mxConstants.STYLE_SHADOW] = true;

        style = graph.getStylesheet().getDefaultEdgeStyle();
        style[mxConstants.STYLE_EDGE] = mxEdgeStyle.TopToBottom;
        style[mxConstants.STYLE_ROUNDED] = true;

        mxEvent.disableContextMenu(container);

        graph.setAutoSizeCells(true);
        graph.setPanning(true);
        graph.panningHandler.useLeftButtonForPanning = true;

        // Installs a popupmenu handler using local function (see below).
        graph.popupMenuHandler.factoryMethod = function(menu, cell, evt) {
            return createPopupMenu(graph, menu, cell, evt);
        };

        function createPopupMenu(graph, menu, cell, evt) {
            if (!cell) {
                return;
            }
            if (cell.treeNode){
                currCell = cell;
                menu.addItem('添加条件节点', '', function() {
                    $scope.addNode();
                });
                menu.addItem('添加推论节点', '', function() {
                    $scope.addDedution();
                });
                menu.addItem('删除', '', function() {
                    $scope.deleteNode();
                });
            } else if(cell.treeDedution) {
                currCell = cell;
                menu.addItem('删除', '', function() {
                    $scope.deleteNode();
                });
            }

        }

        var keyHandler = new mxKeyHandler(graph);

        var layout = new mxCompactTreeLayout(graph, false);
        layout.useBoundingBox = false;
        layout.edgeRouting = false;
        layout.levelDistance = 30;
        layout.nodeDistance = 10;
        var layoutMgr = new mxLayoutManager(graph);
        layoutMgr.getLayout = function(cell) {
            if (cell.getChildCount() > 0) {
                return layout;
            }
        };

        //graph.setCellsSelectable(false);
        //禁用折叠功能
        graph.isCellFoldable = function(cell) {
            //return this.model.getOutgoingEdges(cell).length > 0;
            return false;
        };
        graph.cellRenderer.getControlBounds = function(state) {
            if (state.control != null) {
                var oldScale = state.control.scale;
                var w = state.control.bounds.width / oldScale;
                var h = state.control.bounds.height / oldScale;
                var s = state.view.scale;
                return new mxRectangle(state.x + state.width / 2 - w / 2 * s,
                    state.y + state.height + TreeNodeShape.prototype.segment * s - h / 2 * s,
                    w * s, h * s);
            }
            return null;
        };

        graph.foldCells = function(collapse, recurse, cells) {
            this.model.beginUpdate();
            try {
                toggleSubtree(this, cells[0], !collapse);
                this.model.setCollapsed(cells[0], collapse);
                layout.execute(graph.getDefaultParent());
            } finally {
                this.model.endUpdate();
            }
        };

        function toggleSubtree(graph, cell, show) {
            show = (show != null) ? show : true;
            var cells = [];
            graph.traverse(cell, true, function(vertex) {
                if (vertex != cell) {
                    cells.push(vertex);
                }
                return vertex == cell || !graph.isCellCollapsed(vertex);
            });
            graph.toggleCells(show, cells, true);
        }

        var treeId = $routeParams.treeId,
            w = 150, h = 50,
            conditionStyle = 'fillColor=#ccc';

        function updateGraph(fn) {
            graph.getModel().beginUpdate();
            try {
                fn();
            } finally {
                graph.getModel().endUpdate();
            }
        }

        var hasRoot = false;
        function initDecisions() {
            $http({
                method: 'GET',
                url: '/grule-manager/decisionTrees/loadDecision',
                params: {
                    treeId: treeId
                }
            }).success(function(resp){
                if (resp.success) {
                    var data = resp.data,
                        treeNodes = data.treeNodes,
                        treeDedutions = data.treeDedutions;
                    hasRoot = false;
                    updateGraph(function(){
                        var vertexMap = {},
                            edges = [],
                            parent = graph.getDefaultParent(),
                            nodes = [];
                        //添加节点
                        nodes = treeNodes.concat(treeDedutions);
                        nodes = _.sortBy(nodes, 'code');
                        angular.forEach(nodes, function(node){
                            var vertex;
                            if(!node.parentId && !node.nodeId) {
                                vertex = graph.insertVertex(parent, null, formatterCondition(node), graph.container.offsetWidth/2 - 30, 20, w, h, conditionStyle);
                                hasRoot = true;
                                vertex.treeNode = node;
                            } else if (node.parentId) {
                                vertex = graph.insertVertex(parent, null, formatterCondition(node), 0, 0, w, h, conditionStyle);
                                edges.push({
                                    source: node.parentId,
                                    target: node.id
                                });
                                vertex.treeNode = node;
                            } else {
                                vertex = graph.insertVertex(parent, null, formatterDedution(node), 0, 0, w, h);
                                edges.push({
                                    source: node.nodeId,
                                    target: node.id
                                });
                                vertex.treeDedution = node;
                            }
                            vertexMap[node.id] = vertex;
                        });
                        //添加边
                        angular.forEach(edges, function(edge){
                            graph.insertEdge(parent, null, null, vertexMap[edge.source], vertexMap[edge.target]);
                        });
                    });
                }
            });
        }

        var flag = false;
        angular.element(document).off('click', 'li[name="decisionTreeEdit"]').on('click', 'li[name="decisionTreeEdit"]', function () {
            if (!flag) {
                document.getElementById('treePanel').appendChild(container);
                initDecisions();
                flag = true;
            }
        });

        var currCell;
        graph.addListener(mxEvent.CLICK, function(sender, evt) {
            currCell = evt.getProperty('cell');
            if (currCell != null) {
                evt.consume();
            }
        });

        graph.addListener(mxEvent.DOUBLE_CLICK, function(sender, evt) {
            currCell = evt.getProperty('cell');
            if (!currCell) {
                return ;
            }
            if (currCell.treeNode) {
                GillionMsg.showUrl({
                    title: '编辑条件',
                    url: 'rule/decisionTree/condition',
                    data: {
                        modelId: $scope.currPackage.businessModelId,
                        treeNode: currCell.treeNode,
                        status:$rootScope.currPackage.status,
                        packageId:$scope.currPackage.id
                    },
                    width: 880,
                    height: 500,
                    onClose: function(resp) {
                        if (resp.success) {
                            var treeNode = resp.treeNode;
                            updateGraph(function(){
                                currCell.treeNode = treeNode;
                                graph.getModel().setValue(currCell, formatterCondition(treeNode));
                            });
                        }
                    }
                });
            } else if (currCell.treeDedution) {
                GillionMsg.showUrl({
                    title: '编辑推论',
                    url: 'rule/decisionTree/dedution',
                    data: {
                        modelId:$scope.currPackage.businessModelId,
                        treeDedution: currCell.treeDedution,
                        status:$rootScope.currPackage.status,
                        packageId:$scope.currPackage.id
                    },
                    width: 880,
                    height: 500,
                    onClose: function(resp) {
                        if (resp.success) {
                            var treeDedution = resp.treeDedution;
                            updateGraph(function(){
                                currCell.treeDedution = treeDedution;
                                graph.getModel().setValue(currCell, formatterDedution(treeDedution));
                            });
                        }
                    }
                });
            }
            evt.consume();
        });

        $scope.addNode = function() {
            if (currCell && currCell.treeNode) {
                GillionMsg.showUrl({
                    title: '添加条件',
                    url: 'rule/decisionTree/condition',
                    data: {
                        modelId: $scope.currPackage.businessModelId,
                        treeNode: {
                            treeId: treeId,
                            parentId: currCell.treeNode.id
                        },
                        status:$rootScope.currPackage.status,
                        packageId:$scope.currPackage.id
                    },
                    width: 880,
                    height: 500,
                    onClose: function(resp) {
                        if (resp.success) {
                            var treeNode = resp.treeNode;
                            updateGraph(function(){
                                var parent = graph.getDefaultParent();
                                var vertex = graph.insertVertex(parent, null, formatterCondition(treeNode), 0, 0, w, h, conditionStyle);
                                vertex.treeNode = treeNode;
                                graph.insertEdge(parent, null, null, currCell, vertex);
                            });
                        }
                    }
                });
            } else if(!hasRoot) {
                GillionMsg.showUrl({
                    title: '添加条件',
                    url: 'rule/decisionTree/condition',
                    data: {
                        modelId: $scope.currPackage.businessModelId,
                        treeNode: {
                            treeId: treeId
                        },
                        status:$rootScope.currPackage.status,
                        packageId:$scope.currPackage.id
                    },
                    width: 880,
                    height: 500,
                    onClose: function(resp) {
                        if (resp.success) {
                            var treeNode = resp.treeNode;
                            updateGraph(function(){
                                var parent = graph.getDefaultParent();
                                var vertex = graph.insertVertex(parent, null, formatterCondition(treeNode), graph.container.offsetWidth/2 - 30, 20, w, h, conditionStyle);
                                vertex.treeNode = treeNode;
                                hasRoot = true;
                            });
                        }
                    }
                });
            } else {
                GillionMsg.alert('提示', '请先选中条件节点');
            }
        };

        $scope.addDedution = function() {
            if (currCell && currCell.treeNode) {
                GillionMsg.showUrl({
                    title: '添加推论',
                    url: 'rule/decisionTree/dedution',
                    data: {
                        modelId:$scope.currPackage.businessModelId,
                        treeDedution: {
                            treeId: treeId,
                            nodeId: currCell.treeNode.id
                        },
                        status:$rootScope.currPackage.status,
                        packageId:$scope.currPackage.id
                    },
                    width: 880,
                    height: 500,
                    onClose: function(resp) {
                        if (resp.success) {
                            var treeDedution = resp.treeDedution;
                            var parent = graph.getDefaultParent();
                            updateGraph(function(){
                                var parent = graph.getDefaultParent();
                                var vertex = graph.insertVertex(parent, null, formatterDedution(treeDedution), 0, 0, w, h);
                                vertex.treeDedution = treeDedution;
                                graph.insertEdge(parent, null, null, currCell, vertex);
                            });
                        }
                    }
                });
            } else {
                GillionMsg.alert('提示', '请先选中条件节点');
            }
        };

        function delOrNot(cell) {
            var edges = cell.edges;
            if (!edges) return true;
            if (edges.length>1) {
                return false;
            } else if(edges.length == 1 && edges[0].source == cell) {
                return false;
            } else {
                return true;
            }
        }

        var TreeNodeResource = Resource("/grule-manager/decisionTreeNodes/:id", {
            id: "@id"
        });
        var TreeDedutionResource = Resource("/grule-manager/decisionTreeDedutions/:id", {
            id: "@id"
        });
        $scope.deleteNode = function() {
            if (!currCell) {
                GillionMsg.alert('提示', '请先选中节点');
                return ;
            }
            if (!delOrNot(currCell)) {
                GillionMsg.alert('提示', '该节点存在子节点，不允许删除操作!');
                return ;
            }

            GillionMsg.confirm('提示', '确认要删除!', function(flag){
                if (flag) {
                    updateGraph(function(){
                        if(currCell.treeNode){
                            TreeNodeResource.delete({
                                id:currCell.treeNode.id
                            }, function (response) {
                                if(response.success){
                                    if (!currCell.treeNode.parentId) {
                                        hasRoot = false;
                                    }
                                    currCell = null;
                                }
                            });
                        } else if(currCell.treeDedution) {
                            TreeDedutionResource.delete({
                                id:currCell.treeDedution.id
                            }, function (response) {
                                if(response.success){
                                    currCell = null;
                                }
                            });
                        }
                        graph.removeCells([currCell]);
                    });
                }
            });
        };


        function maxLength(input, maxLength) {
            if (!input) return '';
            var newLen = 0,
                newStr = "",
                chineseRegex = /[^\x00-\xff]/g,
                singleChar = "",
                len = input.replace(chineseRegex,"**").length;
            for(var i = 0;i < len;i++) {
                singleChar = input.charAt(i).toString();
                if(singleChar.match(chineseRegex) != null) {
                    newLen += 2;
                } else {
                    newLen++;
                }
                if(newLen > maxLength) break;
                newStr += singleChar;
            }

            if(len > maxLength) {
                newStr += "...";
            }
            return newStr;
        }

        //格式化显示
        function formatterCondition(treeNode) {
            var result;
            if(treeNode.conditions && treeNode.conditions!='{}' && treeNode.conditions!='') {
                var json = eval("(" + treeNode.conditions + ")");
                result = showValue(json);
            }
            return maxLength(result, 20);
        }

        function formatterDedution(treeDedution) {
            var result="";
            if(treeDedution.dedution && treeDedution.dedution!='{}' && treeDedution.dedution!='') {
                var json = eval("(" + treeDedution.dedution + ")");
                result = setDedution(json);
            }
            return maxLength(result, 20);
        }

        function setDedution(list){
            var result="";
            for(var i=0;i<list.length;i++){
                if(list[i].type=="setRtnValue"){
                    result+="返回:";
                    result+= showValue(list[i].value);
                }else if(list[i].type=="setVariable"){
                    result+="变量赋值:  KEY为:"+list[i].key+",   值为:";
                    result+=showValue(list[i].value);
                }else if(list[i].type=="setModel"){
                    result+="属性赋值:  属性名:"+list[i].modelId+",   值为:";
                    result+=showValue(list[i].modelValue);
                }else if(list[i].type=="breakPackage"){
                    result+="跳出规则包；";
                }else if(list[i].type=="breakAssembly"){
                    result+="跳出决策表；";
                }else if(list[i].type=="execute"){
                    if(list[i].code=="list"){
                        result+="循环"+list[i].source.variableName+"；";
                    }else if(list[i].code=="listEnd"){
                        result+="循环结束；"
                    }else if(list[i].code=="judge"){
                        result+="判断：";
                        result+=showValue(list[i].source);
                    }else if(list[i].code=="judgeEnd"){
                        result+="判断结束；"
                    }
                }
            }
            return result;
        }

        function showValue(json){
            var result="";
            if(json.type=="parenthesis"){
                result +="(";
                result += showValue(json.expression);
                result +=")";
            }else {
                if (json.left != null && json.right != null) {
                    result += showValue(json.left);
                    result += json.oper;
                    result += showValue(json.right);
                } else {
                    if(json.type=="model") {
                        result += json.value;
                    }else if(json.type=="variable"){
                        result += json.variableName;
                    }else if(json.type =="addHours"){
                        result +=showValue(json.source)+"  加"+json.hours +"小时";
                    }else if(json.type=="const"){
                        result +=json.value;
                    }else if(json.type =="lastDateTime"){
                        result +=showValue(json.source)+"  当天最后时间"
                    }else if(json.type =="startWith"){
                        result +=showValue(json.source) +" 以"+json.str+"开始";
                    }else if(json.type =="endsWith"){
                        result +=showValue(json.source) +" 以"+json.str+"结束";
                    }else if(json.type =="matchWith"){
                        result +=showValue(json.source) +" 包含"+json.str;
                    }else if(json.type =="JDBCService"){
                        result +="调用JDBC组件："+showValue(json.sqlName);
                    }else if(json.type =="listValue"){
                        result +="获取"+json.source;
                    }
                }
            }
            return result;
        }
    };
});